package com.mystnihon.crypt;

import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

import com.mystnihon.util.Base64;

public class CryptTool {
    private SecretKey key;
    private Cipher cipher;

    /**
     * @param password
     */
    public CryptTool(String password) {

        try {
            key = createSecretKey(password);
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }

    private static byte[] getPasswordMessageDigest(String password) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
        byte[] passwordMessageDigest = messageDigest.digest(password.getBytes());

        return passwordMessageDigest;
    }

    private static SecretKey createSecretKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] passwordMessageDigest = getPasswordMessageDigest(password);

        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(passwordMessageDigest);

        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128, secureRandom);

        SecretKey secretKey = keyGenerator.generateKey();

        return secretKey;
    }

    /**
     * Encrypt the given data in parameter. It will be encrypted using the key
     * provided in the constructor of {@link CryptTool} and encoded in base-64
     * URL-safe. You can write the returned string in the shared preferences.
     * 
     * @param plainText the text to encrypt.
     * @return Encrypted text encoded in base-64.
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public String encrypt(String plainText) {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] cipherText = cipher.doFinal(plainText.getBytes());
            return new String(Base64.encode(cipherText, Base64.URL_SAFE));
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "";
    }

    /**
     * Decrypt the data.
     * @param codedText
     * @return
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public String decrypt(String codedText) {

        try {
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] encodedText = Base64.decode(codedText.getBytes(), Base64.URL_SAFE);
            return new String(cipher.doFinal(encodedText));
        } catch (InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BadPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "";
    }
}
